package com.zhengqing.common.core.aspect;

import com.zhengqing.common.base.exception.MyException;
import com.zhengqing.common.core.annotaion.LimiterValite;
import com.zhengqing.common.core.util.IpUtil;
import com.zhengqing.common.redis.constant.RedisConstant;
import com.zhengqing.common.redis.util.RedisUtil;
import com.zhengqing.common.web.util.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 日志切面
 * </p>
 *
 * @author zhengqingya
 * @description
 * @date 2020/8/1 19:09
 */
@Slf4j
@Aspect
@Component
public class LimiterAspect {

    /**
     * 配置织入点
     */
    @Pointcut("@annotation(com.zhengqing.common.core.annotaion.LimiterValite)")
    public void limiterPointCut() {
    }

    @Around("limiterPointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ServletUtil.getRequest();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        LimiterValite limiterValite = signature.getMethod().getAnnotation(LimiterValite.class);
        if (!limiterValite(request, limiterValite.seconds(), limiterValite.count())){
            throw new MyException(20000,"请求过于频繁");
        }
        // 处理业务
        Object result = joinPoint.proceed();
        return result;
    }

    private Boolean limiterValite(HttpServletRequest request,int seconds,int count){
        String ip = IpUtil.getRequestClientRealIp(request);
        String key = RedisConstant.CATALOG_EMAIL_LIMITER_KEY+ip;
        if (!RedisUtil.hasKey(key)){
            RedisUtil.setEx(key,"1",seconds, TimeUnit.SECONDS);
            return true;
        }else {
            Long increment = RedisUtil.incrBy(key, 1L);
            if (increment == 1){
                RedisUtil.expire(key,seconds,TimeUnit.SECONDS);
            }
            if (increment > count){
                return false;
            }
            return true;
        }
    }

}
